package org.yaac.server.file;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.yaac.server.util.AutoBeanUtil;
import org.yaac.server.util.FileUtil;
import org.yaac.shared.file.BlobUploadResult;
import org.yaac.shared.file.BlobUploadResult.Status;

import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;

/**
 * @author Max Zhu (thebbsky@gmail.com)
 *
 */
public class BlobUploadServlet extends HttpServlet {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private final Logger logger;

	@Inject
	BlobUploadServlet(Logger logger) {
		super();
		this.logger = logger;
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String resultStr = null;
		
		// Create a new file upload handler
		try {
			FileItemIterator i = new ServletFileUpload().getItemIterator(req);

			// step1 : extract data from the request
			String fileName = null;
			byte[] rawData = null;
			
			while (i.hasNext()) {
				FileItemStream item = i.next();
				 
				InputStream stream = item.openStream();
				
				byte [] content = FileUtil.toByteArray(stream);
				
				try {
					if (item.isFormField()) {	// filename					
						fileName = new String(content);
					} else {	// rawdata
						rawData = content;		
					}	
				} finally {
					stream.close();
				}
			}
			
			// step 2 : save file into blobstore
			FileService fileService = FileServiceFactory.getFileService();
			// TODO : make mimetype configurable by user
			AppEngineFile file = fileService.createNewBlobFile("text/plain", fileName);
			
			// Open a channel to write to it
			FileWriteChannel writeChannel = fileService.openWriteChannel(file, true);
			writeChannel.write(ByteBuffer.wrap(rawData));			
			writeChannel.closeFinally();
			
			logger.info("Uploaded file name : " + fileName + " path : " + file.getFullPath() + " with size = " + rawData.length);
			
			// step 3 : send result back to client
			BlobUploadResult result = AutoBeanUtil.newBlobUploadResult(Status.SUCCESS, fileName, rawData.length);
			resultStr = AutoBeanUtil.encode(BlobUploadResult.class, result);
		} catch (FileUploadException e) {
			logger.log(Level.SEVERE, "failed to save file", e);
			
			BlobUploadResult result = AutoBeanUtil.newBlobUploadResult(Status.FAIL, null, null);
			resultStr = AutoBeanUtil.encode(BlobUploadResult.class, result);
		} catch (IOException e) {
			logger.log(Level.SEVERE, "failed to save file", e);
			
			BlobUploadResult result = AutoBeanUtil.newBlobUploadResult(Status.FAIL, null, null);
			resultStr = AutoBeanUtil.encode(BlobUploadResult.class, result);
		}
		
		// make sure the plain json will be sent back
		resp.setContentType("text/html"); 
		resp.getWriter().print(resultStr);
	}
}
